package com.ld.shieldsb.dao.model;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType;
import com.ld.shieldsb.annotation.field.link.Link;
import com.ld.shieldsb.annotation.field.link.Many2Many;
import com.ld.shieldsb.annotation.util.AnnotationUtil;
import com.ld.shieldsb.annotation.util.TableNameUtil;
import com.ld.shieldsb.common.core.collections.ListUtils;
import com.ld.shieldsb.common.core.model.Description;
import com.ld.shieldsb.common.core.reflect.ClassUtil;
import com.ld.shieldsb.common.core.util.StringUtils;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Data
@Slf4j
public class JoinModel {
    private Class<?> mainClass;
    private QueryModel mainQueryModel;
    private String mainTableName; // 表名
    private String mainTableAlias = "tbmain"; // 表别名
    private int index = 0;

    private String sql;
    protected List<Object> params = new ArrayList<Object>();

    private List<JoinLinkedTableModel> linked; // 连表对象

    public JoinModel() {
        super();
    }

    public JoinModel(Class<?> mainClass, QueryModel mainQueryModel) {
        this.mainClass = mainClass;
        this.mainQueryModel = mainQueryModel;
    }

    public String getMainTableName() {
        if (mainTableName == null) {
            mainTableName = TableNameUtil.getTableName(mainClass);
        }
        return mainTableName;
    }

    public List<JoinLinkedTableModel> addLinkedTable(JoinLinkedTableModel linkedModel) {
        if (linked == null) {
            linked = new ArrayList<>();
        }
        if (linked.contains(linkedModel)) {
            log.error("表别名重复" + linkedModel);
            return null;
        }
        linked.add(linkedModel);
        return linked;
    }

    /**
     * 添加一一对应的关联
     * 
     * @Title addLinkedTable
     * @author 吕凯
     * @date 2019年8月16日 下午4:53:42
     * @param field
     * @param queryModel
     * @return List<JoinLinkedTableModel>
     */
    public List<JoinLinkedTableModel> addLinkedTable(Field field, QueryModel queryModel) {
        JoinLinkedTableModel linkedModel = new JoinLinkedTableModel();
        linkedModel.setField(field);
        linkedModel.setQueryModel(queryModel);
        Class<?> fieldType = null;
        if (field.isAnnotationPresent(Many2Many.class)) {
            Many2Many manyAnno = field.getAnnotation(Many2Many.class);
            fieldType = manyAnno.relation();
            // 主类中关联字段
            Description fieldDescFrom = AnnotationUtil.getFieldDescription(field.getDeclaringClass(), manyAnno.from());
            if (fieldDescFrom != null) {
                String fromDBName = fieldDescFrom.getDbName(); // 目标对象的主键对应数据库中的名字
                linkedModel.setLinkfromCulumn(fromDBName); //
            }
            // 从表中对应主类的字段
            Description fieldDescRelationFrom = AnnotationUtil.getFieldDescription(manyAnno.relation(), manyAnno.relationFrom());
            if (fieldDescRelationFrom != null) {
                String relationFromDBName = fieldDescRelationFrom.getDbName(); // 目标对象的主键对应数据库中的名字
                linkedModel.setLinkThisCulumn(relationFromDBName);
            }

        } else if (field.isAnnotationPresent(Link.class)) {
            Link linkAnno = field.getAnnotation(Link.class);
            fieldType = ClassUtil.getFieldPojoType(field); // 获取field内对象的类型，集合类型返回泛型
            // 主类中关联字段
            Description fieldDescFrom = AnnotationUtil.getFieldDescription(field.getDeclaringClass(), linkAnno.field());
            if (fieldDescFrom != null) {
                String fromDBName = fieldDescFrom.getDbName(); // 目标对象的主键对应数据库中的名字
                linkedModel.setLinkfromCulumn(fromDBName);
            }
            // 从表中对应主类的字段
            Description fieldDesctarget = AnnotationUtil.getFieldDescription(fieldType, linkAnno.targetField());
            if (fieldDesctarget != null) {
                String targetFieldDBName = fieldDesctarget.getDbName(); // 目标对象的主键对应数据库中的名字
                linkedModel.setLinkThisCulumn(targetFieldDBName);
            }
        }
        linkedModel.setTableName(TableNameUtil.getTableName(fieldType)); // 表名
        if (queryModel.getJoinType() != null) { // 优先从queryModel中取
            linkedModel.setJoinType(queryModel.getJoinType());
        }
        if (StringUtils.isNotEmpty(queryModel.getJoinTableAlias())) { // 表别名，优先从queryModel中取
            linkedModel.setTableAlias(queryModel.getJoinTableAlias());
        } else {
            linkedModel.setTableAlias("tb" + index++);
        }
        queryModel.setJoinTableAlias(linkedModel.getTableAlias()); // 表别名，设置会queryMode中
        linkedModel.setLinkfromTable(getMainTableAlias());
        return addLinkedTable(linkedModel);
    }

    /**
     * 添加多对多的关联
     * 
     * @Title addLinkedTable
     * @author 吕凯
     * @date 2019年8月16日 下午4:53:27
     * @param field
     * @param middleQueryModel
     * @param queryModel
     * @return List<JoinLinkedTableModel>
     */
    public List<JoinLinkedTableModel> addLinkedTable(Field field, QueryModel middleQueryModel, QueryModel queryModel) {
        if (field.isAnnotationPresent(Many2Many.class)) {
            // 添加中间表关联
            JoinLinkedTableModel linkedMiddleModel = new JoinLinkedTableModel();
            linkedMiddleModel.setField(field);
            linkedMiddleModel.setQueryModel(middleQueryModel);
            Many2Many manyAnno = field.getAnnotation(Many2Many.class);
            Class<?> fieldType = manyAnno.relation();
            if (middleQueryModel.getJoinType() != null) { // 优先从queryModel中取
                linkedMiddleModel.setJoinType(queryModel.getJoinType());
            }
            linkedMiddleModel.setTableName(TableNameUtil.getTableName(fieldType)); // 表名
            if (StringUtils.isNotEmpty(queryModel.getJoinTableAlias())) {// 表别名，优先从queryModel中取
                linkedMiddleModel.setTableAlias(queryModel.getJoinTableAlias());
            } else {
                linkedMiddleModel.setTableAlias("tb" + index++);
            }
            middleQueryModel.setJoinTableAlias(linkedMiddleModel.getTableAlias()); // 表别名，设置会queryMode中
            linkedMiddleModel.setLinkfromTable(getMainTableAlias());
            // 主类中关联字段
            Description fieldDescFrom = AnnotationUtil.getFieldDescription(field.getDeclaringClass(), manyAnno.from());
            if (fieldDescFrom != null) {
                String fromDBName = fieldDescFrom.getDbName(); // 目标对象的主键对应数据库中的名字
                linkedMiddleModel.setLinkfromCulumn(fromDBName);
            }

            // 从表中对应主类的字段
            Description fieldDescRelationFrom = AnnotationUtil.getFieldDescription(manyAnno.relation(), manyAnno.relationFrom());
            if (fieldDescRelationFrom != null) {
                String relationFromDBName = fieldDescRelationFrom.getDbName(); // 目标对象的主键对应数据库中的名字
                linkedMiddleModel.setLinkThisCulumn(relationFromDBName);
            }

            addLinkedTable(linkedMiddleModel);

            // 添加多对多另一对象的关联
            JoinLinkedTableModel linkedModel = new JoinLinkedTableModel();
            linkedModel.setField(field);
            linkedModel.setQueryModel(queryModel);
            fieldType = ClassUtil.getFieldPojoType(field); // 获取field内对象的类型，集合类型返回泛型
            if (queryModel.getJoinType() != null) { // 优先从queryModel中取
                linkedModel.setJoinType(queryModel.getJoinType());
            }
            linkedModel.setTableName(TableNameUtil.getTableName(fieldType)); // 表名
            if (StringUtils.isNotEmpty(queryModel.getJoinTableAlias())) { // 表别名，优先从queryModel中取
                linkedModel.setTableAlias(queryModel.getJoinTableAlias());
            } else {
                linkedModel.setTableAlias("tb_" + field.getName());
            }
            queryModel.setJoinTableAlias(linkedModel.getTableAlias()); // 表别名，设置会queryMode中
            linkedModel.setLinkfromTable(linkedMiddleModel.getTableAlias());

            // 主类中关联字段
            Description fieldDescRelationTo = AnnotationUtil.getFieldDescription(manyAnno.relation(), manyAnno.relationTo());
            if (fieldDescRelationTo != null) {
                String relationToDBName = fieldDescRelationTo.getDbName(); // 目标对象的主键对应数据库中的名字
                linkedModel.setLinkfromCulumn(relationToDBName);
            }

            // 从表中对应主类的字段
            Description fieldDescTo = AnnotationUtil.getFieldDescription(fieldType, manyAnno.to());
            if (fieldDescTo != null) {
                String toDBName = fieldDescTo.getDbName(); // 目标对象的主键对应数据库中的名字
                linkedModel.setLinkThisCulumn(toDBName);
            }

            addLinkedTable(linkedModel);
        }
        return linked;
    }

    public String getSqlAndParams() {

        StringBuilder selectSb = new StringBuilder(); // select部分
        StringBuilder joinSb = new StringBuilder(); // join部分
        StringBuilder queryStrSb = new StringBuilder(); // 查询条件
        StringBuilder queryStrSbJoin = new StringBuilder(); // 关联表查询条件
        if (ListUtils.isNotEmpty(linked)) {
            linked.forEach(linkedModel -> {
                String joinTableName = linkedModel.getTableName();
                String joinTableAlias = linkedModel.getTableAlias();
                String linkfromTable = linkedModel.getLinkfromTable();
                String linkfromCulumn = linkedModel.getLinkfromCulumn();
                String joinCulumn = linkedModel.getLinkThisCulumn();
                if (selectSb.length() > 0) {
                    selectSb.append(",");
                }
                selectSb.append(getSelectFieldsStr(linkedModel.getQueryModel(), joinTableAlias)); // 获取搜索字符串
                if (linkedModel.getJoinType() == JoinType.JOIN || linkedModel.getJoinType() == JoinType.INNER_JOIN
                        || linkedModel.getJoinType() == JoinType.LEFT_OUTER_JOIN
                        || linkedModel.getJoinType() == JoinType.RIGHT_OUTER_JOIN) {
                    joinSb.append(linkedModel.getJoinType().name);
                }
                joinSb.append(String.format(" %s  %s ON %s.%s = %s.%s ", joinTableName, joinTableAlias, linkfromTable, linkfromCulumn,
                        joinTableAlias, joinCulumn));

            });
        }

        String mainCondition = mainQueryModel.getNoOrderQueryStrCondition(getMainTableAlias());
        if (StringUtils.isNotEmpty(mainCondition)) {
            queryStrSb.append(" WHERE ").append(mainCondition); // 主表的查询条件，需要增加排序
        }
        this.params.clear();
        // 参数赋值
        // 1、主表的查询参数
        if (mainQueryModel.getParams() != null && mainQueryModel.getParams().length > 0) {
            this.params.addAll(Arrays.asList(mainQueryModel.getParams()));
        }
        // 2、关联表的查询参数
        if (ListUtils.isNotEmpty(linked)) {
            linked.forEach(linkedModel -> {
                QueryModel queryModel = linkedModel.getQueryModel();
                String queryStr = queryModel.getNoOrderQueryStrCondition(queryModel.getJoinTableAlias());
                if (StringUtils.isNotEmpty(queryStr)) {
                    queryStrSbJoin.append(" AND ").append(queryStr); // 关联表的查询条件
                }
                if (queryModel.getParams() != null && queryModel.getParams().length > 0) {
                    this.params.addAll(Arrays.asList(queryModel.getParams()));
                }

            });
        }
        String queryStr = (queryStrSb.toString() + queryStrSbJoin.toString()).trim(); // 主表和关联表的查询条件拼接
        if (queryStr.startsWith(" AND ")) { // 如果以AND 开头，表示主表没有查询条件，需要将第一个AND替换为WHERE
            queryStr = queryStr.replaceFirst(" AND ", " WHERE ");
        }
        if (queryStr.equals(" WHERE ")) { // 如果以WHERE结尾，即没有查询条件，移除
            queryStr = " ";
        }
        // 拼语句
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT ");
        sb.append(getSelectFieldsStr(getMainQueryModel(), getMainTableAlias())); // 获取搜索字符串);
        if (selectSb.length() > 0) {
//            sb.append(",").append(selectSb); // 获取join表的搜索字符串;返回的字段中不带前缀暂时不能区分对象，先隐藏 ，待处理TODO
        }
        sb.append(" FROM ");
        sb.append(getMainTableName());
        sb.append(" ");
        sb.append(mainTableAlias);
        sb.append(" ");
        if (queryStrSbJoin.length() > 0 || mainQueryModel.getJoinMust()) { // 如果从表没有查询条件，不需要关联了
            sb.append(joinSb);
        }
        sb.append(queryStr);

        sb.append(mainQueryModel.getOrder(getMainTableAlias())); // 排序

        this.sql = sb.toString();
        return sql;
    }

    /**
     * 获取搜索字符串
     * 
     * @Title getSelectFieldsStr
     * @author 吕凯
     * @date 2019年8月19日 下午2:27:25
     * @param queryModel
     * @param joinTableAlias
     * @return String
     */
    private String getSelectFieldsStr(QueryModel queryModel, String joinTableAlias) {
        StringBuilder selectSb = new StringBuilder();
        String selectField = queryModel.getSelectFields(); // 查询字段
        if (StringUtils.isNotEmpty(selectField)) {
            if (selectField.equals("*")) {
                selectSb.append(joinTableAlias).append(".*");
            } else {
                List<String> selectFieldList = Arrays.asList(selectField.split(","));
                List<String> selectFieldListNew = new ArrayList<>();
                selectFieldList.forEach(fields -> {
                    selectFieldListNew.add(joinTableAlias + "." + fields);
                });
                selectSb.append(String.join(",", selectFieldListNew));
            }
        }
        return selectSb.toString();
    }

    public Object[] getParams() {
        return params.toArray();
    }

}
